package zheezes.eisp.collect.model.impl.wt;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;

import zheezes.eisp.collect.model.CollectTaskHandler;
import zheezes.eisp.data.orm.CollectTask;
import zheezes.eisp.data.orm.Concentrator;
import zheezes.eisp.data.orm.DataBean;
import zheezes.eisp.data.orm.DataType;
import zheezes.eisp.data.orm.ResMeter;
import zheezes.protocol.Frame;
import zheezes.protocol.impl.wt.DataUnit;
import zheezes.protocol.impl.wt.WtConAddr;
import zheezes.protocol.impl.wt.WtFrame;
import zheezes.protocol.impl.wt.du.Ctrl1EDi0243DataUnit;
import zheezes.protocol.impl.wt.du.Ctrl1EDi0247DataUnit;
import zheezes.protocol.impl.wt.du.Ctrl9EDi0243DataUnit;
import zheezes.protocol.impl.wt.du.Ctrl9EDi0247DataUnit;
import zheezes.protocol.impl.wt.meta.FrzData;
import zheezes.protocol.impl.wt.meta.FrzDate;
import zheezes.protocol.impl.wt.meta.WtMtAddr;
import zheezes.socket.Transput;
import zheezes.util.ByteUtil;
import zheezes.util.DateFormatUtil;
import zheezes.util.DateUtil;


import com.ibm.icu.util.Calendar;

public class WtRrzDataCollectTaskHandler extends CollectTaskHandler {
	private static Logger logger = Logger.getLogger(WtRrzDataCollectTaskHandler.class);
	private Concentrator con;
	// private List<ResMeter> mtlist;

	private List<Date> loadFrzTimeList(int seq) {
		List<Date> dlist = null;

		WtFrame frame = new WtFrame();
		// frame.setCtrl(ctrl);
		frame.setRtua(new WtConAddr(con.getLogicAddr()));
		Ctrl1EDi0247DataUnit du = new Ctrl1EDi0247DataUnit();
		du.setSeq(seq);
		frame.addDataUnit(du);

		Transput transput;
		if ((transput = postOffice.send(frame)) != null) {
			Frame[] recv = null;
			if (transput.await() == Transput.SUCCESS && (recv = transput.getRecv()) != null) {
				dlist = new ArrayList<Date>();
				for (Frame f : recv) {
					WtFrame frm = (WtFrame) f;
					for (DataUnit d : frm.getDataUnits()) {
						Ctrl9EDi0247DataUnit dd = (Ctrl9EDi0247DataUnit) d;
						Date[] ds = dd.getDateList();
						dlist.addAll(Arrays.asList(ds));
					}
				}
			}
		}

		return dlist;
	}

	private List<Date> loadFrzTimeList() {
		List<Date> list = new ArrayList<Date>();
		for (int i = 0; i < 2; i++) {
			List<Date> l = loadFrzTimeList(i);
			if (l != null) {
				list.addAll(l);
			} else {
				return null;
			}
		}
		Date td = task.getDataDate();
		Iterator<Date> it = list.iterator();
		while (it.hasNext()) {
			Date d = it.next();
			if (d == null || DateUtil.compare(d, td, Calendar.DATE) != 0) {
				it.remove();
			}
		}
		return list;
	}

	private int collSdtFrzData(Date date, List<ResMeter> mls) {
		int count = 0;
		while(mls.size() > 0) {
			WtFrame frame = new WtFrame();
			frame.setRtua(new WtConAddr(con.getLogicAddr()));
			Ctrl1EDi0243DataUnit du = new Ctrl1EDi0243DataUnit();
			du.setFrzDate(date);
			Iterator<ResMeter> iter = mls.iterator();
			while (iter.hasNext()) {
				ResMeter rm = iter.next();
				if(du.addMt(new WtMtAddr(rm.getNo())) == 0) {
					iter.remove();
				} else {
					break;
				}
			}
			frame.addDataUnit(du);
			
			Transput transput;
			if ((transput = postOffice.send(frame)) != null) {
				Frame[] recv = null;
				if (transput.await() == Transput.SUCCESS && (recv = transput.getRecv()) != null) {
					task.setCommSuccNum(task.getCommSuccNum() + 1);
					for (Frame f : recv) {
						WtFrame frm = (WtFrame) f;
						for (DataUnit d : frm.getDataUnits()) {
							Ctrl9EDi0243DataUnit dd = (Ctrl9EDi0243DataUnit) d;
							FrzDate fd = dd.getFrzDate();
							Map<WtMtAddr, FrzData> map = dd.getFrzData();
							for (Entry<WtMtAddr, FrzData> e : map.entrySet()) {
								if(saveFrzData(fd, e.getKey(), e.getValue()) == 0) {
									count++;
								}
							}
						}
					}
				} else {
					break;
				}
			}
		}
		return count;
	}
	
	private int saveFrzData(FrzDate fd, WtMtAddr addr, FrzData data) {
		DataBean db = new DataBean();
		db.setMtno(addr.toString());
		DataType type = dataAccessor.getDataTypeByHex("0243");
		db.setTypeid(type.getId());
		db.setFrzDate(fd.getDate());
		byte[] buf = new byte[fd.size() + addr.size() + data.size()];
		int idx = 0;
		idx += fd.getBytes(buf, idx);
		idx += addr.getBytes(buf, idx);
		idx += data.getBytes(buf, idx);
		if(idx != buf.length) {
			logger.error("save froze data error, length is not match");
		}
		db.setValue(new String(ByteUtil.atos(buf, "%02x")));
		return dataAccessor.saveData(db);
	}

	public void run() {
		try {
			boolean succ = true;
			int cnt = 0;
			// task.setCollectTimes(task.getCollectTimes() + 1);
			con = dataAccessor.getConById(task.getConId());
			if(con != null) {
				// mtlist = dataAccessor.queryResMeterByCon(con.getId());
				List<Date> dlist = loadFrzTimeList();
				if(dlist != null) {
					for (Date d : dlist) {
						logger.info(DateFormatUtil.getDttmFmt().format(d));
						List<ResMeter> mls = dataAccessor.queryConNoFrzDataResMeter(con.getId(), d);
						int ecnt = mls.size(); // the mls will be modify in collSdtFrzData, so I will keep the count 
						int c = collSdtFrzData(d, mls);
						cnt += c;
						if(c < ecnt) { // if the expect count equals with read count
							succ = false;
						} else if(c > ecnt) {
							logger.error(String.format("expect = %d < get = %d ", ecnt, c));
						}
					}	
				}
				if(succ) {
					task.setStatus(CollectTask.STATUS_FINISH);
				}
			} else {
				task.setStatus(CollectTask.STATUS_FINISH);
			}
			task.setCollectedNum(task.getCollectedNum() + cnt);
			task.setRunTimes(task.getRunTimes() + 1);
			task.setLastRunDate(new Date());
			// dataAccessor.saveCollectTask(task);
			dataAccessor.updateCollectTask(task);
		} catch (Exception e) {
			logger.debug(e.getMessage(), e);
		}
	}
}
